package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.srb.common.exception.Assert;
import com.atguigu.srb.common.exception.BusinessException;
import com.atguigu.srb.common.result.ResponseEnum;
import com.atguigu.srb.core.enums.BorrowerStatusEnum;
import com.atguigu.srb.core.enums.LendStatusEnum;
import com.atguigu.srb.core.enums.ReturnMethodEnum;
import com.atguigu.srb.core.enums.TransTypeEnum;
import com.atguigu.srb.core.hfb.HfbConst;
import com.atguigu.srb.core.hfb.RequestHelper;
import com.atguigu.srb.core.mapper.*;
import com.atguigu.srb.core.pojo.entity.*;
import com.atguigu.srb.core.pojo.vo.BorrowInfoApprovalVO;
import com.atguigu.srb.core.service.LendService;
import com.atguigu.srb.core.util.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 标的准备表 服务实现类
 * </p>
 *
 * @author lsyandwh
 * @since 2022-12-02
 */
@Transactional
@Service
public class LendServiceImpl extends ServiceImpl<LendMapper, Lend> implements LendService {

    @Autowired
    private BorrowInfoMapper borrowInfoMapper;

    @Autowired
    private DictMapper dictMapper;

    @Autowired
    private BorrowerMapper borrowerMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Autowired
    private TransFlowMapper transFlowMapper;

    @Autowired
    private LendItemMapper lendItemMapper;

    @Autowired
    private LendReturnMapper lendReturnMapper;

    @Autowired
    private LendItemReturnMapper lendItemReturnMapper;

    @Override
    public List<Lend> lendList() {

        List<Lend> list = baseMapper.selectList(null);

        QueryWrapper<BorrowInfo> wrapper = new QueryWrapper<>();

        list.forEach(lend -> {

            wrapper.clear();
            wrapper.eq("id",lend.getBorrowInfoId());

            BorrowInfo borrowInfo = borrowInfoMapper.selectOne(wrapper);
            Integer returnMethod = borrowInfo.getReturnMethod();
            String method = DictUtils.getDictName(dictMapper, "returnMethod", returnMethod);

            Map<String,Object> map = new HashMap<>();
            map.put("returnMethod",method);
            map.put("status",LendStatusEnum.getMsgByStatus(lend.getStatus()));

            lend.setParam(map);
        });

        return list;
    }

    @Override
    public Map<String, Object> show(Long id) {

        //获取标的信息
        Lend lend = baseMapper.selectById(id);
        Map<String,Object> lendMap = new HashMap<>();
        lendMap.put("status", LendStatusEnum.getMsgByStatus(lend.getStatus()));
        lendMap.put("returnMethod",DictUtils.getDictName(dictMapper,"returnMethod",lend.getReturnMethod()));
        lend.setParam(lendMap);

        //获取借款人信息
        QueryWrapper<Borrower> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",lend.getUserId());
        Borrower borrower = borrowerMapper.selectOne(wrapper);

        Map<String,Object> borrowerMap = new HashMap<>();

        borrowerMap.put("education",DictUtils.getDictName(dictMapper,"education",borrower.getEducation()));
        borrowerMap.put("income",DictUtils.getDictName(dictMapper,"income",borrower.getIncome()));
        borrowerMap.put("sex",borrower.getSex() == 1 ? "男" : "女");
        borrowerMap.put("marry",borrower.getMarry() ? "是" : "否");
        borrowerMap.put("industry",DictUtils.getDictName(dictMapper,"industry",borrower.getIndustry()));
        borrowerMap.put("returnSource",DictUtils.getDictName(dictMapper,"returnSource",borrower.getReturnSource()));
        borrowerMap.put("status", BorrowerStatusEnum.getMsgByStatus(borrower.getStatus()));
        borrower.setParam(borrowerMap);

        //封装数据
        Map<String,Object> result = new HashMap<>();
        result.put("lend",lend);
        result.put("borrower",borrower);

        return result;
    }

    @Override
    public BigDecimal getInterestCount(BigDecimal invest, BigDecimal yearRate, Integer totalmonth, Integer returnMethod) {

        BigDecimal interestCount;
        //计算总利息
        if (returnMethod.intValue() == ReturnMethodEnum.ONE.getMethod()) {
            interestCount = Amount1Helper.getInterestCount(invest, yearRate, totalmonth);
        } else if (returnMethod.intValue() == ReturnMethodEnum.TWO.getMethod()) {
            interestCount = Amount2Helper.getInterestCount(invest, yearRate, totalmonth);
        } else if(returnMethod.intValue() == ReturnMethodEnum.THREE.getMethod()) {
            interestCount = Amount3Helper.getInterestCount(invest, yearRate, totalmonth);
        } else {
            interestCount = Amount4Helper.getInterestCount(invest, yearRate, totalmonth);
        }
        return interestCount;
    }

    @Override
    public void makeLoan(Long id) {

        //1.获取标的信息
        Lend lend = baseMapper.selectById(id);

        // 调用汇付宝放款接口，传入lendId
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("agentId", HfbConst.AGENT_ID);
        paramMap.put("agentProjectCode", lend.getLendNo());// 标的单号
        paramMap.put("agentBillNo", lend.getLendNo());// 放款单号
        paramMap.put("mchFee", lend.getExpectAmount());// 平台收取的手续费
        paramMap.put("timestamp", RequestHelper.getTimestamp());//放款时间
        paramMap.put("sign", RequestHelper.getSign(paramMap));//验证参数
        System.out.println("调用汇付宝，放款接口");

        //发送同步远程调用
        JSONObject result = RequestHelper.sendRequest(paramMap, HfbConst.MAKE_LOAD_URL);

        //判断放款是否成功
        Assert.equals(result.getString("resultCode"),"0000", ResponseEnum.ERROR);

        //获取返回数据
        String agentBillNo = (String) result.get("agentBillNo");//放款单号
        String voteAmt = (String) result.get("voteAmt");//放款金额
        String mchFee = (String) result.get("mchFee");//平台手续费

        //更新标的信息
        lend.setRealAmount(new BigDecimal(mchFee));//平台实际收益
        lend.setStatus(LendStatusEnum.PAY_RUN.getStatus());//还款中
        lend.setLendStartDate(LocalDate.now());//开始日期
        lend.setLendEndDate(LocalDate.now().plusMonths(lend.getPeriod()));//结束日期
        lend.setPaymentTime(LocalDateTime.now());//放款时间
        lend.setPaymentAdminId(1L);
        baseMapper.updateById(lend);

        //更新借款人账户信息
        QueryWrapper<UserAccount> borrowerUpdateWrapper = new QueryWrapper<>();
        borrowerUpdateWrapper.eq("user_id",lend.getUserId());
        UserAccount borrowerUserAccount = userAccountMapper.selectOne(borrowerUpdateWrapper);
        borrowerUserAccount.setAmount(borrowerUserAccount.getAmount().add(new BigDecimal(voteAmt)));//账户金额
        userAccountMapper.updateById(borrowerUserAccount);

        //获取借款人用户信息
        UserInfo borrowerUserInfo = userInfoMapper.selectById(lend.getUserId());

        //生成借款人交易流水
        TransFlow borrowerTransFlow = new TransFlow();
        borrowerTransFlow.setUserId(borrowerUserInfo.getId());
        borrowerTransFlow.setUserName(borrowerUserInfo.getName());
        borrowerTransFlow.setTransNo(agentBillNo);//交易单号
        borrowerTransFlow.setTransType(TransTypeEnum.BORROW_BACK.getTransType());
        borrowerTransFlow.setTransTypeName(TransTypeEnum.BORROW_BACK.getTransTypeName());
        borrowerTransFlow.setTransAmount(new BigDecimal(voteAmt));//交易金额
        borrowerTransFlow.setMemo("标的放款到账");
        transFlowMapper.insert(borrowerTransFlow);

        //更新投资人账户信息
        QueryWrapper<LendItem> lendItemQueryWrapper = new QueryWrapper<>();
        lendItemQueryWrapper.eq("lend_id",lend.getId());
        List<LendItem> lendItems = lendItemMapper.selectList(lendItemQueryWrapper);
        int i = 0;
        for (LendItem lendItem : lendItems) {
            i ++;
            //获取投资人账户信息
            QueryWrapper<UserAccount> userAccountQueryWrapper = new QueryWrapper<>();
            userAccountQueryWrapper.eq("user_id",lendItem.getInvestUserId());
            UserAccount userAccount = userAccountMapper.selectOne(userAccountQueryWrapper);
            //更新投资人冻结账户金额
            userAccount.setFreezeAmount(userAccount.getFreezeAmount().subtract(lendItem.getInvestAmount()));
            userAccountMapper.updateById(userAccount);

            //查询投资人信息
            UserInfo userInfo = userInfoMapper.selectById(lendItem.getInvestUserId());

            //生成交易流水
            TransFlow transFlow = new TransFlow();
            transFlow.setUserId(userInfo.getId());
            transFlow.setUserName(userInfo.getName());
            transFlow.setTransNo(agentBillNo + i);//交易单号
            transFlow.setTransType(TransTypeEnum.INVEST_UNLOCK.getTransType());
            transFlow.setTransTypeName(TransTypeEnum.INVEST_UNLOCK.getTransTypeName());
            transFlow.setTransAmount(lendItem.getInvestAmount());//交易金额
            transFlow.setMemo("投资放款");
            transFlowMapper.insert(transFlow);
        }
        //生成还款计划回款计划
        createLendReturn(lend,lendItems);
    }

    /**
     * 生成还款计划
     * @param lend
     * @param lendItems
     */
    private void createLendReturn(Lend lend,List<LendItem> lendItems){

        //获取期数
        Integer period = lend.getPeriod();

        for (int i = 1;i <= period;i++){

            LendReturn lendReturn = new LendReturn();

            lendReturn.setLendId(lend.getId());//标的id
            lendReturn.setBorrowInfoId(lend.getBorrowInfoId());//借款信息id
            lendReturn.setReturnNo(LendNoUtils.getReturnNo());//还款批号
            lendReturn.setUserId(lend.getUserId());
            lendReturn.setAmount(lend.getAmount());//借款金额
            lendReturn.setBaseAmount(getBaseAmount(lend,i));
            lendReturn.setCurrentPeriod(i);//当前期数
            lendReturn.setLendYearRate(lend.getLendYearRate());//年化利率
            lendReturn.setReturnMethod(lend.getReturnMethod());//还款方式
            lendReturn.setFee(new BigDecimal("0"));//手续费
            lendReturn.setOverdue(false);//是否逾期
            lendReturn.setOverdueTotal(new BigDecimal("0"));//逾期金额
            lendReturn.setLast(false);//是否最后一次还款
            lendReturn.setStatus(0);
            if(i == period){
                lendReturn.setLast(true);
            }
            lendReturnMapper.insert(lendReturn);

            //本金
            BigDecimal principal = new BigDecimal("0");
            //利息
            BigDecimal interest = new BigDecimal("0");

            for (LendItem lendItem : lendItems) {
                Map<String,BigDecimal> map = createLendItemReturn(lend,lendItem,lendReturn,i);
                principal = principal.add(map.get("principal"));
                interest = interest.add(map.get("interest"));
            }

            lendReturn.setPrincipal(principal);//本金
            lendReturn.setInterest(interest);//利息
            lendReturn.setTotal(principal.add(interest));//本息

            lendReturnMapper.updateById(lendReturn);
        }
    }

    /**
     * 生成计息本金
     * @param lend
     * @param i
     * @return
     */
    private BigDecimal getBaseAmount(Lend lend, int i) {
        BigDecimal baseAmount = lend.getAmount();// 借款总额
        //查询还款计划
        QueryWrapper<LendReturn> wrapper = new QueryWrapper<>();
        wrapper
                .eq("lend_id", lend.getId())
                .lt("current_period", i);
        List<LendReturn> lendReturns = lendReturnMapper.selectList(wrapper);
        //如果有数据则减去之前的本金
        if (null != lendReturns || lendReturns.size() > 0) {
            for (LendReturn lendReturn : lendReturns) {
                baseAmount = baseAmount.subtract(lendReturn.getPrincipal());
            }
        }
        //如果没有数据则返回总借款金额
        return baseAmount;
    }

    /**
     * 生成回款计划
     */
    private Map<String,BigDecimal> createLendItemReturn(Lend lend,LendItem lendItem,LendReturn lendReturn,Integer period){

        Map<String,BigDecimal> map = new HashMap<>();
        LendItemReturn lendItemReturn = new LendItemReturn();
        lendItemReturn.setLendId(lend.getId());//标的id
        lendItemReturn.setLendItemId(lendItem.getId());//标的项id
        lendItemReturn.setLendReturnId(lendReturn.getId());//标的还款id
        lendItemReturn.setInvestUserId(lendItem.getInvestUserId());//投资人id
        lendItemReturn.setInvestAmount(lendItem.getInvestAmount());//投资金额
        lendItemReturn.setCurrentPeriod(period);//期数
        lendItemReturn.setLendYearRate(lend.getLendYearRate());//年化率
        lendItemReturn.setReturnMethod(lend.getReturnMethod());//还款方式
        lendItemReturn.setFee(new BigDecimal("0"));//手续费
        lendItemReturn.setOverdue(false);//是否逾期
        lendItemReturn.setOverdueTotal(new BigDecimal("0"));//逾期金额
        lendItemReturn.setStatus(0);//状态

        if (lend.getReturnMethod() == 1) {
            Map<Integer, BigDecimal> perMonthInterest = Amount1Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            Map<Integer, BigDecimal> perMonthPrincipal = Amount1Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            map.put("principal", perMonthPrincipal.get(period));
            map.put("interest", perMonthInterest.get(period));
        }
        if (lend.getReturnMethod() == 2) {
            Map<Integer, BigDecimal> perMonthInterest = Amount2Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            Map<Integer, BigDecimal> perMonthPrincipal = Amount2Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            map.put("principal", perMonthPrincipal.get(period));
            map.put("interest", perMonthInterest.get(period));
        }
        if (lend.getReturnMethod() == 3) {
            Map<Integer, BigDecimal> perMonthInterest = Amount3Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            Map<Integer, BigDecimal> perMonthPrincipal = Amount3Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            map.put("principal", perMonthPrincipal.get(period));
            map.put("interest", perMonthInterest.get(period));
        }
        if (lend.getReturnMethod() == 4) {
            Map<Integer, BigDecimal> perMonthInterest = Amount4Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            Map<Integer, BigDecimal> perMonthPrincipal = Amount4Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            map.put("principal", perMonthPrincipal.get(1));
            map.put("interest", perMonthInterest.get(1));
        }
        lendItemReturn.setInterest(map.get("interest"));//本金
        lendItemReturn.setPrincipal(map.get("principal"));//利息
        BigDecimal add = map.get("interest").add(map.get("principal"));
        lendItemReturn.setTotal(add);//本息
        lendItemReturnMapper.insert(lendItemReturn);
        return map;
    }
}
